# pyplusplus script
#
import sys, re, os, os.path, time, logging, glob, copy
import distutils.sysconfig
import goodies.goodie_perf_overrides
from goodies import *

import pygccxml

import elementtree.ElementTree as et
import xml.parsers.expat

import settings, core_info

pj = os.path.join

# TODO:
# - Implement finalize  (needs testing)
# - Ensure objects are stored as RefPtrs and auto converted to RefPtrs
# - Wrap begin/end edit
#
script_start_time = time.time()
work_start_time = None
use_profiler = False
use_query_opt = True

# Setup global settings
set_recursive_default(False)
sys.setrecursionlimit( sys.getrecursionlimit() * 10)   # Need a little more room for bindings
set_logger_level(logging.INFO)
#set_logger_level(logging.DEBUG)
import pyplusplus.code_creators.calldef
pyplusplus.code_creators.calldef.use_enum_workaround = True

class LocalTemplateBuilder:
   """ Template builder helper class.
       This class is meant to simplify the use of templates with py++.
   """
   
   def __init__(self):
      """ Initialize template builder. """
      # List of tuples: (templateTypename, typedefName)
      #       ex: ("MyClass<float>","myclass_float")
      self.mTemplates = []
   
   def Template(self, templateType, typedefName=None):
      """Add a template to instantiate.
      
      @param templateType: Fully instantiated name.  (ex: TemplateClass<float> )
      @param typedefName:  Name of type def to define to this template type.
          This name can then be used later to look up the real fully
          expanded template type from the typedef map.
      """
      if not typedefName:
         typedefName = self.cleanTemplateName(templateType)
      self.mTemplates.append( (templateType, typedefName) )

   def buildTemplateFileContents(self):
      """ Build up the contents of a file to instantiate the needed templates.
          headerFiles - List of header files for this module.
      """
      if len(self.mTemplates) == 0:
         return None
      
      content = "/** Autogenerated temporary file for template instantiation. */\n"
      for t in self.mTemplates:
         template_type = t[0]
         typedef_name = t[1]
         content += """
            typedef %(template_type)s %(typedef_name)s;
            inline unsigned __instantiate_%(typedef_name)s()
            { return unsigned(sizeof(%(typedef_name)s)); }
         """ % vars()      
      
      return content
   
   def cleanTemplateName(self, templateName):
      """ Build a clean template name. """
      clean_re = re.compile('[:<>\s,]')
      return clean_re.sub('_', templateName)
   
# -- Helper methods --- #
def buildContainerHeader(headers, extraContent="/** Nothing Extra */", filename=None):
   """ Build up a header containing a bunch of other headers.
       headers - List of header files for this module.
       returns a temp file or a file created with filename.
   """
   if filename == None:
      filename = pygccxml.utils.create_temp_file_name(suffix=".h")   
   content = "/** Auto-generated temporary file for header containment. */\n"
   for h in headers:
      content += '#include <%s>\n'%h
   content += '\n\n'
   content += extraContent
   content += '\n\n'
   
   temp_file = file(filename, 'w')
   temp_file.write(content)
   temp_file.close()
      
   return filename

class FCPolicyResolver(object):
   """ Call policy resolver for field containers and OpenSG classes.
       Based on default_policy_resolver and return_value_policy_resolver
       Trys to do as much automatically as possible to wrap OpenSG methods.
   """
   def __init__(self):      
      self.__const_char_pointer = pointer_t(const_t(char_t()))
      self.__const_wchar_pointer = pointer_t(const_t(wchar_t()))
      self.getSF_re = re.compile('getSF.*')
      self.getMF_re = re.compile('getMF.*')
      self.get_re = re.compile('get.*')   
      self.create_re = re.compile('create.*')
      
   def __call__(self,calldef, hint=None):
      if not isinstance( calldef, calldef_t ):
         return None
      
      if isinstance(calldef, constructor_t):
         return None

      # Build up helper variables
      ret_type = remove_alias( calldef.return_type )
      naked_type = remove_cv(remove_reference(ret_type))
      rt_is_const = is_const(ret_type) or (hasattr(ret_type,'base') and is_const(ret_type.base))
      rt_is_ref = is_reference(ret_type) or (hasattr(ret_type,'base') and is_reference(ret_type.base))
      rt_is_pointer = is_pointer(ret_type)
      rt_is_class = is_class(naked_type)
      
      #print "method: [%s] is_ref:%s is_const:%s is_pointer:%s is_class:%s"%\
      #        (calldef.name,rt_is_ref,rt_is_const, rt_is_pointer,rt_is_class)
      #print_declarations(calldef,detailed=True,recursive=True)

      # Custom methods
      if calldef.name in ["getType","getClassType","getClass","getStaticClass"]:
         print "   part of default return internal reference methods."
         return return_internal_reference()
      
      # Creation methods return new objects
      # - Only something special when returning ptr, smart_ptr handled already
      if self.create_re.match(calldef.name) and rt_is_pointer:
         return return_value_policy(manage_new_object)
      
      # Handle singleton method
      if "the" == calldef.name:
         return return_value_policy(reference_existing_object)
      
      # Check for default cases of:
      # - const_char_pointer, wchar ptr
      # - fundamental type (ref and non ref
      if is_same( naked_type, self.__const_char_pointer ):
         return default_call_policies()
      if is_same( ret_type, self.__const_wchar_pointer ):
         return return_value_policy( return_by_value )
      if isinstance( naked_type, fundamental_t ):
         if rt_is_ref:
            return return_value_policy(return_by_value)
         else:
            return default_call_policies()
      
      #if isinstance( ret_type, declarations.reference_t ) \
      #   and isinstance( ret_type.base, declarations.const_t ):
      if rt_is_const and rt_is_ref and rt_is_class:
         return return_value_policy( copy_const_reference )
      
      # Check gets and [] for things returning internal references
      if self.get_re.match(calldef.name) or \
            (hasattr(calldef,'symbol') and calldef.symbol == '[]'):
         if rt_is_ref:
            if is_fundamental( naked_type ) or is_enum( naked_type ):
               if is_const:
                  return return_value_policy(copy_const_reference)
               else:
                  return return_value_policy(copy_non_const_reference)
            elif rt_is_const:
               return return_value_policy(copy_const_reference)
            else:
               return return_internal_reference()
         elif rt_is_pointer:
            if rt_is_const:
               return default_call_policies()
            else:
               return return_internal_reference()
         
      # Handle Image:: returning const *. For now try this in general
      if rt_is_const and rt_is_pointer:
         return return_internal_reference()
      
      return None

# The FCPolicyResolver instance to use
fc_policy_resolver = FCPolicyResolver()

def handleClassDefaults(cls):   
   """ Perform default processing on the given class.
       This includes just about everything we can do by
       default to change methods exposed, call policies, etc.
   """   
   exclude_protected(cls)
   wrap_const_ref_params(cls)
   
   # Remove parameters that we don't want exposed   
   for p in ["isNodeCore","newPtr"]:
      cls.decls(p,allow_empty=True).exclude()
      
   # Hide all Mask variables
   # - these don't expose well and osg2 will not have them anyway
   cls.variables(regex_matcher(".*Mask"), allow_empty=True).exclude()
   cls.variables(regex_matcher("stat.*"), allow_empty=True).exclude()
   cls.variables(allow_empty=True).exclude()
   
   all_calldefs = cls.calldefs()
   contained_names = set()
   for c in all_calldefs:
      contained_names.add(c.name)   
   
   for n in contained_names:
      #print "  checking calldef: [%s]"%n,
      methods = cls.calldefs(n)
      #print "  found num: ", len(methods)

      # Resolve the call policies on any methods left
      for m in methods:
         
         # These operations on chunks, materials, images cause problems
         # with boost.python because of protected destructor
         if isinstance(m, operator_t) and m.symbol in ["<","==","!="]:         
            m.exclude()
            continue
         
         m.call_policies = fc_policy_resolver(m)    

def addFCPtrCode(c, mb, className, parentName=None, setHeldType=True):
   # Set the held type for the FC type to a ref ptr
   refPtrType_str = "OSG::%sRefPtr"%className
   if setHeldType:
      c.held_type = refPtrType_str

   # Add the __cmp__ and __hash__ operations
   #add_member_function(c, "__cmp__","pyopensg::cmp_ref_ptrs<%s>"%refPtrType_str)
   #add_member_function(c, "__hash__","pyopensg::hash_ref_ptr<%s>"%refPtrType_str)
   
   # Add on the ptr conversion methods needed
   ##c.add_registration_code("bp::register_ptr_to_python< OSG::%sPtr >();"%cinfo.name, works_on_instance=False)
   c.add_registration_code("pyopensg::register_fcptr<%s>::execute();"%refPtrType_str, works_on_instance=False)
   c.add_registration_code("bp::implicitly_convertible< OSG::%sRefPtr, OSG::%sPtr >();"%(className,className), works_on_instance=False)
   if parentName:
      #c.add_registration_code("bp::implicitly_convertible< OSG::%sPtr, OSG::%sPtr >();"%(className,parentNamet), works_on_instance=False)   
      c.add_registration_code("bp::implicitly_convertible< OSG::%sRefPtr, OSG::%sRefPtr >();"%(className,parentName), works_on_instance=False)      
   mb.add_registration_code("/** Helpers for: %s */"%className)
   ##mb.add_registration_code('bp::def("RefPtr", &pyopensg::ToRefPtr<OSG::%sPtr>);'%className)
   mb.add_registration_code('bp::def("FCPtr", &pyopensg::ToFcPtr<OSG::%sPtr>);'%className)



def main():
   # --- Collect all settings for build ---- #
   opensg_inc_dir = os.path.join(os.popen('osg-config --prefix','r').readline().strip(),
                                 'include')
   opensg_cflags = os.popen('osg-config --cflags System Base','r').readline().strip()
   opensg_cflags = opensg_cflags.replace("-use_readonly_const","")
   
   opensg_src_dir = "/home/allenb/Source/OpenSG/Source"                           
   boost_inc_dir = "/home/allenb/Source/boost"
   python_inc_dir = distutils.sysconfig.get_python_inc()
   output_dir = "osg_module"
   main_header_filename = os.path.join(output_dir,'osgmodule_mainheader.h')
   defines = ["OSG_WITH_GLUT",
              "OSG_WITH_TIF","OSG_WITH_JPG","OSG_WITH_PNG","OSG_WITH_GIF",
              "_OSG_HAVE_CONFIGURED_H_",]
   
   gccxml_path = ""
   inc_path = [output_dir, opensg_inc_dir, boost_inc_dir, python_inc_dir]
   
   
   # --- Search for .fcd files and build up class info ------- #
   print "Auto-building list of node cores using .fcd files... "
   fcd_files = []
   core_infos = core_info.core_infos   # Use dictionary so we could override in the future
   
   for p in ["Base","System","WindowSystem/GLUT"]:
      for dirpath,dirs,files in os.walk(os.path.join(opensg_src_dir,p)):
         fcd_files += [os.path.join(dirpath,f) for f in files if f.endswith(".fcd")]
   
   #print "found .fcd files: ", fcd_files
   if 1:
      for f in fcd_files:
         #print "fcd: ", f
         try:
            tree = et.parse(f)
            fc_elt = tree.getroot()
            assert fc_elt.tag == "FieldContainer"
            attribs = fc_elt.attrib.copy()
            parent = attribs["parent"]
            name = attribs["name"]
         except xml.parsers.expat.ExpatError, ex:
            #print "Error parsing file: %s"%f
            #print str(ex)
            #print "Trying re method instead. "
   
            file_text = file(f).read()
            name = re.search('name=\"(.*?)\"',file_text).group(1)
            parent = re.search('parent=\"(.*?)\"',file_text).group(1)
            library = re.search('library=\"(.*?)\"',file_text).group(1)
   
         # Build up the class info
         #print "   name: %s  parent: %s"%(name,parent)
         if not core_infos.has_key(name) and not (name in core_info.core_ignore_list):
            core_infos[name] = core_info.CoreInfo(name,parent)
   print "Node cores found: ", len(core_infos) 
   
   # ------ Manually define headers files -------- #
   # These includes are added later to the module builder
   extra_includes = ["OsgPtrHelpers.h",
                     "boost/python/suite/indexing/map_indexing_suite.hpp",
                     "boost/python/suite/indexing/vector_indexing_suite.hpp"]
   
   all_headers = []
   
   type_headers = ["OpenSG/OSGTypeBase.h",
                 "OpenSG/OSGMemoryObject.h",
                 "OpenSG/OSGDataType.h",
                 'OpenSG/OSGFieldType.h',
                 'OpenSG/OSGBaseTypes.h',
                 'OpenSG/OSGField.h',
                 'OpenSG/OSGFieldFactory.h',
                 'OpenSG/OSGFieldDescription.h',
                 'OpenSG/OSGFieldContainerType.h',
                 'OpenSG/OSGFieldContainerFactory.h',
                 'OpenSG/OSGFieldContainer.h',              
                 'OpenSG/OSGField.h',              
                 'OpenSG/OSGChangeList.h',              
                 ]
                 
   math_headers = ["OpenSG/OSGVolume.h",           
                 "OpenSG/OSGVector.h",
                 "OpenSG/OSGColor.h",
                 "OpenSG/OSGMatrix.h",
                 'OpenSG/OSGQuaternion.h',
                 'OpenSG/OSGPlane.h',
                 'OpenSG/OSGDynamicVolume.h',
                 ]
                 
   free_func_headers = ['OpenSG/OSGStatCollector.h',
                 'OpenSG/OSGBaseFunctions.h',
                 'OpenSG/OSGFieldContainerPtr.h',
                 "OpenSG/OSGSceneFileHandler.h",               
                  "OpenSG/OSGGraphOpSeq.h",
                  "OpenSG/OSGSimpleGeometry.h"
                 ]
   
   misc_headers = ["OpenSG/OSGFieldContainerPtr.h",
                   "OpenSG/OSGAttachmentPtr.h",
                   'OpenSG/OSGAttachmentContainerPtr.h',
                   'OpenSG/OSGNodePtr.h',
                   'OpenSG/OSGBinaryDataHandler.h',
                   'OpenSG/OSGStringConversionStateBase.h',
                   'OpenSG/OSGSimpleAttachments.h',
                   'OpenSG/OSGDrawAction.h',
                   'OpenSG/OSGEdgeIterator.h',
                   'OpenSG/OSGTriangleIterator.h',
                   'OpenSG/OSGPrimitiveIterator.h',
                   'OpenSG/OSGFaceIterator.h',
                   'OpenSG/OSGLineIterator.h',
                   'OpenSG/OSGState.h',
                   'OpenSG/OSGBackground.h',
                   'OpenSG/OSGLightEnv.h',
                   'OpenSG/OSGDrawTreeNode.h',
                   'OpenSG/OSGBrick.h',
                   "OpenSG/OSGGeoTypeGraphOp.h",
                   "OpenSG/OSGGraphOpFactory.h",
                   "OpenSG/OSGGraphOp.h",
                   "OpenSG/OSGGraphOpSeq.h",
                   "OpenSG/OSGMakeTransparentGraphOp.h",
                   "OpenSG/OSGMaterialMergeGraphOp.h",
                   "OpenSG/OSGMergeGraphOp.h",
                   "OpenSG/OSGPruneGraphOp.h",
                   "OpenSG/OSGSharePtrGraphOp.h",
                   "OpenSG/OSGSingleTypeGraphOp.h",
                   "OpenSG/OSGSplitGraphOp.h",
                   "OpenSG/OSGStripeGraphOp.h",
                   "OpenSG/OSGVerifyGeoGraphOp.h",
                   "OpenSG/OSGVerifyGraphOp.h",
                   ]
   
   wrapper_headers = ["ColorWrapper.h", 
                    "Wrappers.h",
                    "VecStorageWrappers.h",]
   
   core_headers = []
      
   core_infos = core_info.core_infos
   for c in core_infos.itervalues():
      core_headers.append("OpenSG/OSG%s.h"%c.name)
      #if c.parent:
      #   core_headers.append("OpenSG/OSG%sBase.h"%c.parent)   
      core_headers.extend(c.includes)
   
   for class_info in core_info.gen_classes:
      core_headers.append("OpenSG/OSG%s.h"%class_info.name)   
      core_headers.extend(class_info.includes)
      
   all_headers = type_headers + math_headers + free_func_headers + misc_headers
   all_headers.extend(wrapper_headers + core_headers)
   
   all_headers_full_paths = []
   for f in all_headers:
      for p in inc_path:
         if os.path.isfile(pj(p,f)):
            all_headers_full_paths.append(pj(p,f))
            continue
   
   #all_headers = base_osg_headers + wrapper_headers
   
   #print "Core: ", core_headers
   
   print "Building PyOpenSG module...."
   print "setting up templates..."
   template_builder = LocalTemplateBuilder()
   tbuilder = TemplateBuilder()   
   
   # Add the math templates
   for vst in settings.vec_storage_typeinfo:
      template_builder.Template(vst.type, vst.alias)
   
   for vt in settings.vec_typeinfo:
      template_builder.Template(vt.type, vt.alias)
      
   for pt in settings.pnt_typeinfo:
      template_builder.Template(pt.type, pt.alias) 
   
   #pnt_templates = []
   #for size in settings.pnt_sizes:
   #   for type_str in settings.pnt_types.iteritems():
   #      pnt_temp = tb.Template("osg::Pnt%s%s"%(size, type_str),
   #                             "Pnt%s%s"%(size,type_str))
      
   for ct in settings.color_typeinfo:
      template_builder.Template(ct.type, ct.alias) 
         
   
   mat_temp = tbuilder.Template("osg::Matrix", "Matrix")
   quat_temp = tbuilder.Template("osg::Quaternion","Quaternion")
   #template_builder.Template("osg::Matrix", "alias_Matrix")
   #template_builder.Template("osg::Quaternion", "alias_Quaternion")
   
   
   # Parse with builder
   print "  creating header file:", main_header_filename
   main_header_filename = buildContainerHeader(all_headers, 
                           template_builder.buildTemplateFileContents() + tbuilder.buildAutogenContents(),
                           filename=main_header_filename)
   
   print "creating builder and parsing."
   cache_file = "pypp.pyopensg.cache"
   
   mb = ModuleBuilder([main_header_filename],
                      working_directory = ".",
                      include_paths=inc_path,
                      cache=cache_file+".module",                                        
                      define_symbols=defines,
                      ignore_gccxml_output=True,
                      optimize_queries=use_query_opt,                                     
                      cflags=opensg_cflags,
                      dependent_headers=all_headers_full_paths)
   tbuilder.processTemplates(mb)
   mb.BOOST_PYTHON_MAX_ARITY = 21
   mb.global_ns.exclude()
   osg = mb.global_ns.namespace("osg", recursive=False)
   
   global work_start_time
   work_start_time = time.time()
   
   if False:
      decl_file = file("decl_out_early.txt",'w', 1024000)
      print "Writing out decls to file... ",
      mb.print_declarations(osg, writer=decl_file.write)
      #mb.print_declarations(my_class)
      decl_file.close()
      print "done."
   
   #mb.print_declarations()
   #mb.print_declarations(my_class)
   
   # ------------ Helper methods and data -------------------- #
   
   # Map from template alias name to real decl wrapper type
   print "Building template alias map..."
   template_alias_db = {}
   global_typedefs = mb.global_ns.typedefs()
   
   for td in global_typedefs:
      template_alias_db[td.name] = td.type 
         
   
   print "# ---------------  Base Memory and Field Types ----------------- #"
   
   # Expose classes
   # - Memory/Type classes
   tb = osg["TypeBase"]
   tb.include()       # finalize
   finalize(tb)
   mo = osg["MemoryObject"]
   mo.include()

   dt = osg["DataType"]
   dt.include()
   
   # - Field classes
   ft = osg["FieldType"]
   ft.include()      #.finalize()
   ft["_createMethod"].exclude()
   finalize(ft)
   
   ff = osg.class_("FieldFactory") #.finalize()   
   ff.include()
   ff["createField"].call_policies = return_value_policy(manage_new_object)
   ff["getFieldType"].call_policies  = return_internal_reference()
   ff["the"].call_policies = return_value_policy(reference_existing_object)
   ff["_fieldTypeM"].exclude()
   finalize(ff)
   
   fd = osg.class_("FieldDescription")  #.finalize()   
   fd.include()
   fd["getFieldType"].call_policies = return_internal_reference()
   fd["getField"].call_policies = return_internal_reference()
   for d in ["setAccessMethod","setIndexAccessMethod","_fAccessMethod","_fIndexedAccessMethod"]:
      fd[d].exclude()
   finalize(fd)
   
   fct = osg.class_("FieldContainerType")    #.finalize()   
   fct.include()
   fct["getParent"].exclude()
   fct["addDescription"].exclude()
   fct["subDescription"].exclude()
   fct["getFieldDescription"].call_policies = return_internal_reference()
   fct["findFieldDescription"].call_policies = return_internal_reference()
   finalize(fct)
   
   fcf = osg.class_("FieldContainerFactory")     #.finalize()
   finalize(fcf)
   fcf.include()
   for m in ["findType","findUninitializedType","getFieldContainerStore"]:
      fcf[m].call_policies  = return_internal_reference()
   fcf["the"].call_policies = return_value_policy(reference_existing_object)
   fcf["_the"].exclude()
   

   f = osg.class_("Field")             #.finalize()   
   f.include()
   for m in ["getType","getContentType","getValueByStr"]:
      f[m].call_policies = return_internal_reference()
   osg.class_("ChangeList").include()
   finalize(f)
   
   null_fc = osg.class_("NullFieldContainerPtr")
   null_fc.include()
   finalize(null_fc)
   
   
   # ----------------- Base Math types --------------- #
   print "---------------------------------------------------"
   print "Base Math Type"
   
   #typedefs = osg.typedefs(re_matcher(".*"))
   #print "OSG Typedefs:"
   #for td in typedefs:
   #   print "%s -- %s -- %s"%(td.name, td.alias, td.type)
   
   #typedefs = mb.global_ns.typedefs(re_matcher(".*"))
   #print "NB Typedefs:"
   #for td in typedefs:
   #   print "%s -- %s -- %s"%(td.name, td.alias, td.type)
   
   # Expose classes   
   v = osg.class_("Volume")    #.finalize()
   finalize(v)
   
   # XXX: Remove constructor that takes pointer types
   # Expose the VecStorage classes
   for vst in settings.vec_storage_typeinfo:
      (size,type_abrv) = (ct.size,ct.type_str)
      cname = template_alias_db[vst.alias].declaration.name       # Lookup true class name by alias
      c = osg.class_(cname)   
      c.include()
      c.rename(vst.exposed_name)
      c["_iSize"].exclude()
      wrap_method(c,"getSeparateValues", 
                   "&osgwrap::VecStorage%s_getSeparateValues_tuple<%s>"%(size,type_abrv))
   
   # VecXX classes
   for vt in settings.vec_typeinfo:   
      c = template_alias_db[vt.alias].declaration.type.declaration
      c.include()
      c.rename(vt.exposed_name)
      c["Null"].exclude()
      c["subZero"].call_policies = return_internal_reference()
      c["addToZero"].call_policies = return_internal_reference()
   
   # PntXX classes
   for pt in settings.pnt_typeinfo:
      #type_name = template_alias_db[pt.alias].declaration.name
      c = template_alias_db[pt.alias].declaration.type.declaration
      c.include()
      #c = osg.class_(cname)
      c.rename(pt.exposed_name)
      c["Null"].exclude()
      c["subZero"][0].call_policies = return_internal_reference()
      #c["addToZero"][0].call_policies = return_internal_reference()
      wrap_method(c,"getValues", "osgwrap::getValues%d<%s>"%(pt.size,pt.type))
   
   # ColorXX classes
   for ct in settings.color_typeinfo:
      (size,type_abrv) = (ct.size,ct.type_str)
      c = template_alias_db[ct.alias].declaration.type.declaration
      c.include()
      c.rename(ct.exposed_name)
      if 3 == size:
         wrap_method(c,"getValuesRGB", "Color3_getValuesRGB_tuple<%s>"%type_abrv)
      else:         
         wrap_method(c,"getValuesRGBA", "Color4_getValuesRGBA_tuple<%s>"%type_abrv)
      wrap_method(c,"getValuesHSV", "Color_getValuesHSV< %s >"%ct.type)
      c.decls("convertToHSV",allow_empty=True).exclude()
      
   # Matrix
   #c = template_alias_db["alias_Matrix"].declaration.type.declaration
   c = mat_temp.decl
   c.include()
   finalize(c)
   wrap_method(c,"getValues", 'osgwrap::getValuesMatrix<float>')     
   c["jacobi"].exclude()
   
   # Quaternion
   #c = template_alias_db["alias_Quaternion"].declaration.type.declaration
   c = quat_temp.decl
   c.include()
   #c.rename("Quaternion")                         #.finalize()
   finalize(c)
   wrap_method(c,"getValues", 'osgwrap::getValues4<osg::QuaternionBase<osg::Real32> >')  
   wrap_method(c,"getValueAsQuat", 'osgwrap::getValues4<osg::QuaternionBase<osg::Real32> >')
   for x in ["getValueAsAxisDeg","getValueAsAxisRad"]:
      c[x].exclude()
   
   # Plane
   c = osg.class_("Plane")
   c.include()
   c["getNormal"].call_policies = return_internal_reference(1)
   c["intersect"].exclude()
   c["intersectInfinite"].exclude()
   
   c = osg.class_("DynamicVolume")            #.finalize()
   c.include()   
   finalize(c)   
   c["getInstance"].call_policies = return_internal_reference(1)
   
   
   print "----------------[ Non-FC Classes ]-------------"
   
   # Standard classes
   for class_info in core_info.gen_classes:
      print "Class: %s"%class_info.name
   
      c = osg.class_(class_info.name)
      c.include()
      #base_c.finalize()
      handleClassDefaults(c)
      for x in class_info.excludes:            
         c[x].exclude()
      for (n,p) in class_info.policies:
         c[n].call_policies = p      
      
   
   c = osg.class_("SceneFileHandler")
   c.include()
   finalize(c)
   handleClassDefaults(c)
   for m in ["getFileType","getPathHandler","getDefaultGraphOp","getOptions",
             "setReadCB","getReadCB","setWriteCB","getWriteCB",
             "getReadProgressCB","setReadProgressCB","setWriteProgressCB","getWriteProgressCB",
             "progressS",
             ]:
      c[m].exclude()
   # Need to do this because _defaultgraphOp is protected and can't be used as a default
   c.calldefs("read").exclude()           #use_default_arguments = False   
   c.calldefs("readTopNodes").exclude()   #use_default_arguments = False   
   c.add_declaration_code("""
static osg::NodePtr sfh_custom_read(osg::SceneFileHandler& sfh, std::string fileName)
{  return sfh.read(fileName.c_str()); }
""")
   add_member_function(c, "read","sfh_custom_read")
   
   
      
   if False:  
      for n in ["GraphOp","MakeTransparentGraphOp","MaterialMergeGraphOp",
                "PruneGraphOp","SharePtrGraphOp","VerifyGeoGraphOp",
                "GeoTypeGraphOp","StripeGraphOp","SplitGraphOp",
                "VerifyGraphOp"]:
         op = osg.class_(n)
         op.include()
         handleClassDefaults(op)
         op.decls("traverseEnter",allow_empty=True).exclude()
         op.decls("traverseLeave",allow_empty=True).exclude()
         
   
   # ----------------- Free functions and basic capabilities --------------- #
   print "---------------------------------------------------"
   print "Misc stuff"
   
   # Base methods
   osg["osgInit"].exclude()     # Add wrapper below to code creator
   osg_exit = osg["osgExit"]
   osg_exit.include()
   
   osg["beginEditCP"].include()
   osg["endEditCP"].include()
   osg["NullFC"].exclude()
   
   add_method(mb,"ptrGetRefCount","&osgwrap::ptrGetRefCount")
   add_method(mb,"ptrGetFieldContainerId","&osgwrap::ptrGetFieldContainerId")
   add_method(mb, "osgInit", "&osgwrap::osgInitWrapper")
   
   for m in core_info.public_methods:
      print "m: %s"%m
      osg[m].include()
   
   # ----------- Generate code for all the Field Containers  --- #
   print "---------------------------------------------------"
   print "Field Containers"
   
   fc = osg.class_("FieldContainer") 
   fc.include()
   for m in ["onCreate","onCreateAspect","onDestroy","executeSyncImpl",
             "NextFieldMask","MTInfluenceMask","newPtr",'isNodeCore']:
      fc[m].exclude()
   for m in ["getType", "getClassType", "getField"]:
      fc[m].call_policies = return_internal_reference()
   finalize(fc)
   addFCPtrCode(fc,mb,"FieldContainer", None, setHeldType=False)
   
   # For each node core class we have information about
   # - Generate for class and classBase
   for (key, cinfo) in core_info.core_infos.iteritems():
      base_name = None
      print "Core: %s"%cinfo.name
   
      # If requested, expose the base
      #if has_base:
      if cinfo.hasBase:
         base_name      = cinfo.name + "Base"
         base_c = osg.class_(base_name)
         base_c.include()
         finalize(base_c)
         handleClassDefaults(base_c)
         #for x in base_excludes:            
         #   base_c[x].exclude()
         #for (n,p) in base_policies:
         #   base_c[n].call_policies = p      
         
      # Expose the core class
      c = osg.class_(cinfo.name)
      c.include()
      finalize(c)      
      handleClassDefaults(c)
      
      for x in cinfo.excludes:
         c[x].exclude()
      for (n,p) in cinfo.policies:
         c[n].call_policies = p      
      
      # Register all the pointer conversions that we need and sets held type
      addFCPtrCode(c, mb, cinfo.name, cinfo.parent)
      
      # Apply mods
      if core_info.core_mods.has_key(key):
         print "Apply mods for: ", key
         for class_mod in core_info.core_mods[key][0]:
            class_mod(c)
         for base_mod in core_info.core_mods[key][1]:
            base_mod(base_c)
   
   # Places that take an osg::NullFC as a default value
   for x in ["createMipmap","scale","reformat","scaleNextPower2","slice","subImage"]:
      osg["Image"][x].use_overload_macro = True   
   
   
   # ------ Standard ------------- #
   # Remove all op=
   all_classes = osg.classes()
   for c in all_classes:
      c.operators(symbol="=", allow_empty=True).exclude()
        
   print "Generating module..."
   
   #Now it is the time to give a name to our module
   mb.build_code_creator(module_name='_osg', enable_indexing_suite=False)
   mb.code_creator.license = '// Licensed LGPL by Allen Bierbaum'
   
   #for h in extra_includes:
   #   mb.code_creator.add_include(h)
      
   # Replace the auto generated list of headers
   #mb.code_creator.replace_included_headers( all_headers + extra_includes)
   mb.code_creator.replace_included_headers( [main_header_filename] + extra_includes)
   
   if False:
      decl_file = file("decl_out.txt",'w', 1024000)
      print "Writing out decls to file... ",
      mb.print_declarations(osg, writer=decl_file.write)
      #mb.print_declarations(my_class)
      decl_file.close()
      print "done."
   
   # So we don't have absolute paths in code
   mb.code_creator.user_defined_directories.append(opensg_inc_dir)
   
   print "Splitting module..."
   mb.split_module(pj(output_dir,'generated'))
   

if use_profiler:
   import hotshot
   profiler = hotshot.Profile('gen_bindings.prof.new5')
   profiler.runcall(main)
   profiler.close()
else:
   main()

print "Code generation complete.  took: %s"%(time.time()-script_start_time,)
print "  start -> work: ", (work_start_time - script_start_time)
print "  work  ->  end: ", (time.time() - work_start_time)


